﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data.Entity;
using SchoolManagerMVC.BusinessAbstract.Interfaces;
using System.Linq.Expressions;
using System.Data.Objects;
using System.Data.Entity.Infrastructure;
using SchoolManagerMVC.BusinessConcrete.Reporting;

namespace SchoolManagerMVC.Repository
{
    public class EFContext:DbContext, IRepository
    {
        public EFContext()
            : base("name=SchoolManagerEntities")
        { }

        public List<EntityT> GetAll<EntityT>() where EntityT :class
        {
            return this.Set<EntityT>().ToList();
        }

        public List<EntityT> GetWhere<EntityT>(Func<EntityT, bool> predicate) where EntityT :class
        {
            return this.Set<EntityT>().Where(predicate).ToList();
        }

        public object GetSingle<EntityT>(Func<EntityT, bool> predicate) where EntityT : class
        {
            return this.Set<EntityT>().Where(predicate).FirstOrDefault();  
        }

        public IMessages Add<EntityT>(EntityT entity) where EntityT : class
        {
            if (entity == null)
            {
                return (new Messages()
                {
                    Message = "Input was empty",
                    result = false
                });
            }
            try
            {
                this.Set<EntityT>().Add(entity);
                this.SaveChanges();
                return (new Messages()
                {
                    Message = "",
                    result = true
                });
            }
            catch (Exception ex)
            {
                if (ex.InnerException == null)
                {
                    return (new Messages()
                    {
                        Message = "An unknown error has ocurred",
                        result = false
                    });
                }
                if (ex.InnerException.ToString().Contains("Violation of UNIQUE KEY constraint"))
                {
                    return (new Messages()
                    {
                        Message = "Input was not unique",
                        result = false
                    });
                }
                return (new Messages()
                {
                    Message = "An unknown error has ocurred",
                    result = false
                });
            }
        }

        public IMessages Remove<EntityT>(EntityT entity) where EntityT : class
        {
            if (entity == null)
            {
                return (new Messages()
                {
                    Message = "Input was empty",
                    result = false
                });
            }
                
            try
            {
                this.Set<EntityT>().Remove(entity);
                this.SaveChanges();
                return (new Messages()
                {
                    Message="",
                    result = true
                });
            }
            catch (Exception ex)
            {
                if (ex.InnerException == null)
                {
                    return (new Messages()
                    {
                        Message = "An unknown error has ocurred",
                        result = false
                    });
                }
                if (ex.InnerException.ToString().Contains("The DELETE statement conflicted with the REFERENCE constraint"))
                {
                    return (new Messages()
                    {
                        Message = "Cannot delete if record is referenced by another record",
                        result = false
                    });
                }
                return (new Messages()
                {
                    Message = "An unknown error has ocurred",
                    result = false
                });
            }
        }

        public void RemoveWhere(Func<string, bool> predicate)
        {
            var list = this.GetWhere(predicate);
            foreach (var curr in list)
            {
                this.Remove(curr);
            }
        }

        public void RemoveSingle<EntityT>(Func<EntityT, bool> predicate) where EntityT:class
        {
            this.Remove(this.GetSingle(predicate));
        }

        public void Update<EntityT>(EntityT entity) where EntityT : class
        {           
            this.ObjectContext.ObjectStateManager.ChangeObjectState(entity, System.Data.EntityState.Modified);
            this.SaveChanges();
        }

        public void UpdateWhere(Func<string, bool> predicate)
        {
            throw new NotImplementedException();
        }

        public void UpdateAt(int index)
        {
            throw new NotImplementedException();
        }


        public List<EntityT> GetWhere<EntityT>(Expression<Func<EntityT, bool>> predicate) where EntityT : class
        {
            throw new NotImplementedException();
        }

        public ObjectContext ObjectContext
        {
            get { return ((IObjectContextAdapter)this).ObjectContext; }
        }
    }    
}
